﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEngine;

namespace IFramework
{
    public class Loom : MonoSingleton<Loom>
    {
        public override void Dispose()
        {
            base.Dispose();
            currentTasks.Clear();
            tasks.Clear();
            delayedTasks.Clear();
            semaphore.Close();
            currentTasks = null;
            tasks = null;
            delayedTasks = null;
            semaphore = null;
        }
        protected override void OnDestroy()
        {
            base.OnDestroy();
        }
        public override void OnSingletonInit()
        {
            currentTasks = new List<LoomDelayedTask>();
            tasks = new List<LoomDelayedTask>();
            delayedTasks = new Queue<LoomDelayedTask>();
            semaphore = new Semaphore(MaxThreadCount, MaxThreadCount);
        }
        private Semaphore semaphore;
        public static int MaxThreadCount = 8;
        private int threadCount;
        private List<LoomDelayedTask> currentTasks;
        private List<LoomDelayedTask> tasks;
        private Queue<LoomDelayedTask> delayedTasks;

        public void RunOnMainThread(Action action, float time = 0.0f)
        {
            if (time != 0)
            {
                lock (delayedTasks)
                {
                    delayedTasks.Enqueue(new LoomDelayedTask(Time.time + time, action));
                }
            }
            else
            {
                lock (tasks)
                {
                   tasks.Add(new LoomDelayedTask(0, action));
                }
            }
        }
        public void RunInChildThread(Action action)
        {
            semaphore.WaitOne();
            Interlocked.Increment(ref threadCount);
            ThreadPool.QueueUserWorkItem((ar)=> { RunTask(action); } );
        }
        private static void RunTask(Action action)
        {
            try
            {
                action();
            }
            catch
            {
            }
            finally
            {
                Interlocked.Decrement(ref Instance.threadCount);
            }

        }

        private void Update()
        {           
            lock (tasks)
            {
                lock (delayedTasks)
                {
                    tasks.AddRange(delayedTasks.Where(d => d.time <= Time.time));
                }
                currentTasks.Clear();
                currentTasks.AddRange(tasks);
                tasks.Clear();
            }
            while (currentTasks.Count != 0)
            {
                currentTasks[0].action();
                currentTasks.RemoveAt(0);
            }
        }
    }
}